# coding=utf-8

import struct
from socket import *
import time, random, re
import binascii
import threading


class Message:
    def __init__(self, vin):
        self.S_FLAG = [0x23, 0x23]
        self.C_FLAG = [0x01]
        self.R_FLAG = [0x01]
        self.VIN = vin.encode('ascii')
        self.E_FLAG = [0x01]
        self.D_LEN = [0x00, 0x00]
        self.D_DATA = bytes()
        self.BCC = 0x00

        self.bytes_message = bytes()
        
    def set_vin_bytes(self,vin):
        self.VIN = vin
    
    def set_data(self, c_flag, r_flag, data):
        self.C_FLAG = [c_flag]
        self.R_FLAG = [r_flag]
        data_len = len(data)
        self.D_LEN = [(data_len >> 8) & 0xFF, data_len & 0xFF]
        self.D_DATA = data

    def get_message(self):
        self.bytes_message = bytes(self.S_FLAG) + bytes(self.C_FLAG) + \
                             bytes(self.R_FLAG) + self.VIN + \
                             bytes(self.E_FLAG) + bytes(self.D_LEN) + \
                             bytes(self.D_DATA)
        for b in self.bytes_message:
            self.BCC ^= b

        self.bytes_message += bytes([self.BCC])
        return self.bytes_message

            
class PlatForm_Server:
    def __init__(self, host='192.168.40.32', port=8888):
        self.HOST = host
        self.PORT = port
        self.sock = socket(AF_INET, SOCK_STREAM)
    
    def start(self):
        if self.start_server():
            pass
            
    def start_server(self):
        try:
            self.sock.bind((self.HOST, self.PORT))
            self.sock.listen(100)
            print ('server waiting...')
            while True:
                conn,addr = self.sock.accept()
                print("accept",addr)
                one_platform = Platform(conn)
                thread = threading.Thread(target=one_platform.start, args=())
                thread.start()
        except Exception as e:
            print("Start Server Fail! %s", e)
            return False
        return True

class Platform:
    def __init__(self,socket,vin='LSVHJ233022221761'):
        self.CMD_MSG = {0x01: ['车辆登入', self.vehicle_login], \
                   0x02: ['事实上报', self.realtime_info], \
                   0x03: ['补发信息', self.realtime_info], \
                   0x04: ['车辆登出', self.vehicle_logout], \
                   0x05: ['平台登入', self.platform_login], \
                   0x06: ['平台登出', self.platform_logout], \
                   0x07: ['心跳', None], \
                   0x08: ['校时', None], \
                   0x80: ['查询', self.process_query], \
                   0x81: ['设置', self.process_set], \
                   0x82: ['控制', self.process_ctrl]}
        self.SUB_CMD_CTRL = {0x01: '远程升级', \
                        0x02: '关机', \
                        0x03: '复位', \
                        0x04: '恢复出厂设置', \
                        0x05: '断开链路', \
                        0x06: '报警', \
                        0x07: '开启链路检测'}
        self.SUB_CMD_PARAM = {0x01: ['车载终端本地存储时间周期',0,self.__decode_word,self.__encode_word], \
                        0x02: ['正常时信息上报时间周期',0,self.__decode_word,self.__encode_word], \
                        0x03: ['报警时信息上报时间周期',0,self.__decode_word,self.__encode_word], \
                        0x04: ['远程服务与管理平台域名长度',4,self.__decode_byte,self.__encode_byte], \
                        0x05: ['远程服务与管理平台域名','SXQC',self.__get_string,self.__encode_string], \
                        0x06: ['远程服务与管理平台端口',22,self.__decode_word,self.__encode_word], \
                        0x07: ['硬件版本','ABC12',self.__get_string,self.__encode_string],\
                        0x08: ['固件版本','DEC12',self.__get_string,self.__encode_string],\
                        0x09: ['车载终端心跳发送周期',0,self.__decode_byte,self.__encode_byte],\
                        0x0A: ['终端应答超时时间',0,self.__decode_word,self.__encode_word],\
                        0x0B: ['平台应答超时时间',0,self.__decode_word,self.__encode_word],\
                        0x0C: ['时间间隔',0,self.__decode_byte,self.__encode_byte],\
                        0x0D: ['公共平台域名长度',4,self.__decode_byte,self.__encode_byte],\
                        0x0E: ['公共平台域名','SXQC',self.__get_string,self.__encode_string],\
                        0x0F: ['公共平台端口',33,self.__decode_word,self.__encode_word],\
                        0x10: ['否处于抽样检测中',0,self.__decode_byte,self.__encode_byte] }
      
        self.sock = socket
        self.VIN  = vin
        
    def start(self):
        self.recv_data()

    def recv_data(self):
        try:
            while True:
                buffer = bytes([])
                buffer = buffer+self.sock.recv(1024)
                data_len = 0
                while len(buffer) > data_len+24:
                    offset, data_len = self.__decode_word(buffer[22:])
                    print("msg data len: %d" % data_len)
                    print("\nRECV:", binascii.b2a_hex(buffer[0:data_len+25]))
                    if buffer[3] != 0xFE:
                        print("收到应答：", self.CMD_MSG[buffer[2]][0], " RESULT:", buffer[3])
                    else:
                        print("收到命令：", self.CMD_MSG[buffer[2]][0])
                        if self.CMD_MSG[buffer[2]][1]:
                            self.CMD_MSG[buffer[2]][1](buffer)
                    buffer = buffer[data_len+25:]
                   
        except Exception as ex:
            pass

    def vehicle_login(self,data):
        print("\t车辆登入")
        
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_vin_bytes(data[4:21])
        result=0x01
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)

    def vehicle_logout(self,data):
        print("\t车辆登出")
        
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_vin_bytes(data[4:21])
        result=0x01
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)
        
    def platform_login(self,data):
        offset = 30
        read_len , id = self.__decode_word(data[offset:])
        offset += read_len
        read_len , username = self.__get_string(data[offset:], size = 12)
        offset += read_len
        read_len , password = self.__get_string(data[offset:], size = 20)
        print("\t平台登入流水号：%d   username=%s  password=%s" % (id, username, password))
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_vin_bytes(data[4:21])
        result=0x01
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)
        
    def platform_logout(self,data):
        read_len , id = self.__decode_word(data[30:])
        print("\t平台登出流水号：%d" % id)
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_vin_bytes(data[4:21])
        result=0x01
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)
        
    def realtime_info(self,data):
        print("\t事实上报")
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_vin_bytes(data[4:21])
        result=0x01
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)
    
    def process_query(self, data):
        print("\t查询参数个数:",data[30])
        values = []
        for i in range(data[30]):
            values.append(self.SUB_CMD_PARAM[data[31+i]][:2])
        print("\t查询数据：",values)
        
        data_body = bytes()
        data_item_len = 0
        for i in range(data[30]):
            pid = data[31+i]
            if pid == 0x05:
                data_body += bytes([0x04])
                data_body += self.SUB_CMD_PARAM[0x04][3](self.SUB_CMD_PARAM[0x04][1])
                data_item_len += 1
            elif pid == 0x0E:
                data_body += bytes([0x0D])
                data_body += self.SUB_CMD_PARAM[0x0D][3](self.SUB_CMD_PARAM[0x0D][1])
                data_item_len += 1
            data_body += bytes([pid])
            data_body += self.SUB_CMD_PARAM[pid][3](self.SUB_CMD_PARAM[pid][1])
            data_item_len += 1
        msg = Message(self.VIN)
        new_data = data[24:24 + 6] + bytes([data_item_len]) + data_body
        msg.set_data(data[2], 0x01, new_data)
        self.send_msg(msg)

    def process_set(self, data):
        print("\t设置参数个数:",data[30])
        values = []
        pids = []
        start_index = 31
        for i in range(data[30]):
            pid = data[start_index]
            pids.append(pid)
            start_index += 1
            if pid == 0x07 or pid == 0x08:
                size, value = self.SUB_CMD_PARAM[pid][2](data[start_index:],5)
                self.SUB_CMD_PARAM[pid][1] = value
                start_index += size
            elif pid == 0x05:
                d_len = self.SUB_CMD_PARAM[0x04][1]
                size, value = self.SUB_CMD_PARAM[pid][2](data[start_index:],d_len)
                self.SUB_CMD_PARAM[pid][1] = value
                start_index += size
            elif pid == 0x0E:
                d_len = self.SUB_CMD_PARAM[0x0D][1]
                size, value = self.SUB_CMD_PARAM[pid][2](data[start_index:],d_len)
                self.SUB_CMD_PARAM[pid][1] = value
                start_index += size
            else:
                size, value = self.SUB_CMD_PARAM[pid][2](data[start_index:])
                self.SUB_CMD_PARAM[pid][1] = value
                start_index += size
        
        for p in pids:
            values.append(self.SUB_CMD_PARAM[p][:2])
        
        print("\t设置数据：",values)
        self.send_universal(data)

    def process_ctrl(self, data):
        print("\t子命令 ID:",data[30])
        if data[30] == 0x06:
            print("\t子命令：", self.SUB_CMD_CTRL[data[30]]," 告警等级：",data[-2])
        elif data[30] == 0x01:
            print("\t子命令：", self.SUB_CMD_CTRL[data[30]])
            prarms_data = data[31:]
            print("\t",self.__decode_upgrade_prarms(prarms_data))
        else:
            print("\t子命令：", self.SUB_CMD_CTRL[data[30]])
        self.send_universal(data)

    def send_universal(self, data, result=0x01):
        # 只保留时间
        data_body = data[24:24 + 6]
        msg = Message(self.VIN)
        msg.set_data(data[2], result, data_body)
        self.send_msg(msg)

    def send_msg(self, msg):
        msg_bytes = msg.get_message()
        print("SEND:", msg_bytes.hex())
        self.sock.send(msg_bytes)
    

    def login(self):
        print("LOGIN:")
        login_body = self.__get_nowtime_bytes() + \
                     bytes([0x00, 0x01]) + self.ICCID.encode('ascii') + \
                     bytes([0x10, 0x00])

        msg = Message(self.VIN)
        msg.set_data(0x01, 0xFE, login_body)
        self.send_msg(msg)
    
    def __decode_upgrade_prarms(self,prarms_data):
        offset = 0;
        end_index ,diaName =  self.__get_string(prarms_data[offset:])
        offset += end_index + 1
        end_index , userName = self.__get_string(prarms_data[offset:])
        offset += end_index + 1
        end_index , passWord = self.__get_string(prarms_data[offset:])
        offset += end_index + 1
        ip_str = self.__get_ip(prarms_data[offset:])
        offset += 6 + 1
        port = prarms_data[offset] * 256 + prarms_data[offset + 1]
        offset += 2 + 1
        end_index , manufactureID = self.__get_string(prarms_data[offset:],4)
        offset += 4 + 1
        end_index , firmwareVersion = self.__get_string(prarms_data[offset:],5)
        offset += 5 + 1
        end_index , softwareVersion = self.__get_string(prarms_data[offset:],5)
        offset += 5 + 1
        end_index , url = self.__get_string(prarms_data[offset:])
        offset += end_index + 1
        timeout = prarms_data[offset] * 256 + prarms_data[offset + 1]
        return (diaName,userName,passWord,ip_str,port,manufactureID,firmwareVersion,softwareVersion,url,timeout)
                               
        
    
    def __get_string(self,sub_data, size = None, end_char = 0x3B):
        buffer =  bytes()
        if size == None:
            for i in range(len(sub_data)):
                if sub_data[i] != end_char:
                    continue
                else:
                    buffer = sub_data[:i]
                    return (i, buffer.decode('ascii'))
        else:
            buffer = sub_data[:size]
            return (size, buffer.decode('ascii'))
            
    def __get_ip(self,sub_data):
        return "%d.%d.%d.%d" % (sub_data[2],sub_data[3],sub_data[4],sub_data[5])
    
    def __get_nowtime_bytes(self):
        t = time.localtime(time.time())
        time_byte = bytes([17, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec])
        return time_byte
    
    def __decode_word(self,sub_data):
        return (2,sub_data[0]*256 + sub_data[1])
    
    def __encode_word(self,word):
        return bytes([(word >> 8) & 0xFF, word & 0xFF])
    
    def __decode_byte(self,sub_data):
        return (1,sub_data[0])
    
    def __encode_byte(self,value):
        return bytes([value])
    
    def __encode_string(self,value):
        return value.encode('ascii')
